
package com.hulk.summary.filter;


import com.hulk.summary.SummaryProperties;
import com.hulk.summary.constant.APICons;
import com.hulk.summary.exception.SummaryException;
import com.hulk.summary.util.JacksonUtils;
import com.hulk.summary.wrapper.RequestWrapper;
import com.hulk.summary.wrapper.ResponseWrapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * summary 过滤器
 *
 * @author hulk
 */
@Slf4j
public class SummaryFilter extends OncePerRequestFilter implements InitializingBean {

    private static final AntPathMatcher pathMatcher = new AntPathMatcher(File.separator);

    private static SummaryProperties properties;

    public SummaryFilter() {

    }

    public SummaryFilter(SummaryProperties p) {
        properties = p;
    }

    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {

        FilterConfig config = this.getFilterConfig();
        boolean go = true;
        // String includePaths = config.getInitParameter(APICons.INCLUDE_PATHS);
        String excludePaths = config.getInitParameter(APICons.EXCLUDE_PATHS);
        List<String> paths = Stream.of(StringUtils.commaDelimitedListToStringArray(excludePaths)).collect(Collectors.toList());
        for (String path : paths) {
            if (pathMatcher.match(path, req.getRequestURI())) {
                go = false;
                break;
            }
        }
        if (go) {
            String excludeFields = config.getInitParameter(APICons.EXCLUDE_FIELDS);
            List<String> excludeList = Stream.of(StringUtils.commaDelimitedListToStringArray(excludeFields)).collect(Collectors.toList());
            RequestWrapper requestWrapper = new RequestWrapper(req, excludeList, properties);
            ResponseWrapper  responseWrapper  = new ResponseWrapper(resp);
            doFilter(requestWrapper, responseWrapper, chain);
            byte[] bytes = responseWrapper.getBytes();
            String plainText = new String (bytes,StandardCharsets.UTF_8);
            boolean jb =  JacksonUtils.isJson(plainText);
            if(jb){
                Map<String,Object> map=  JacksonUtils.readValue(plainText, HashMap.class);
                Map<String,Object> mapTmp=  new HashMap<>();
                Iterator<Map.Entry<String,Object>> it = map.entrySet().iterator();
                while (it.hasNext()){
                    Map.Entry<String,Object> entry = it.next();
                    String key = entry.getKey();
                    if ((!excludeFields.isEmpty()) && excludeFields.contains(key) ){
                        it.remove();
                    }
                    mapTmp.put(key,entry.getValue());
                }
                String signature = ResponseWrapper.createSignature( new TreeMap<>(map),  properties);
                mapTmp.put(properties.getSummaryName(),signature);
                writeException(resp, mapTmp);
            }else{
                //writeException(resp, plainText);
                new SummaryException("请指定响应报文格式为json格式.");
            }
        } else {
            doFilter(req, resp, chain);
        }
    }

    @SneakyThrows
    private void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {
        try {
            chain.doFilter(req, resp);
        } catch (SummaryException e) {
            writeException(resp, e.getMessage());
        } catch (Exception e) {
            writeException(resp, e.getMessage());
        }
    }
    @SneakyThrows
    private void writeException(HttpServletResponse resp, Object message) {
        resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
        PrintWriter wr = resp.getWriter();
        wr.write(JacksonUtils.toJson(message));
        wr.flush();
        wr.close();
    }


}